#include "ftlibcuda.h"
#include <cuda_runtime.h>
#include <cufft.h>
#include <sstream>

static bool cuFft_CheckAvailabilityAndGetVersions(int* pDriverVersion, int* pRuntimeVersion)
{
	// make some CUDA calls in order to check if environment is sane...
	int driverVersion;
	cudaError_t err = cudaDriverGetVersion(&driverVersion);
	if (err != cudaSuccess || driverVersion == 0)
	{
		// If no driver is installed, then 0 is returned as the driver version (via driverVersion).
		return false;
	}

	int runTimeVersion;
	err = cudaRuntimeGetVersion(&runTimeVersion);
	if (err != cudaSuccess)
	{
		return false;
	}

	int deviceCount;
	err = cudaGetDeviceCount(&deviceCount);
	if (err != cudaSuccess || deviceCount == 0)
	{
		return false;
	}

	if (pDriverVersion != nullptr)
	{
		*pDriverVersion = driverVersion;
	}

	if (pRuntimeVersion != nullptr)
	{
		*pRuntimeVersion = runTimeVersion;
	}

	return true;
}

bool cuFft_CheckAvailability()
{
	return cuFft_CheckAvailabilityAndGetVersions(nullptr, nullptr);
}

static bool copyToDestString(const char* szSrc, char* szDest, size_t* pLength)
{
	if (pLength == nullptr)
	{
		return false;
	}

	size_t l = strlen(szSrc);

	if (*pLength <= l)
	{
		*pLength = l;
		return false;
	}

	if (szDest != nullptr)
	{
		strcpy_s(szDest, *pLength, szSrc);
	}

	*pLength = l;
	return true;
}

bool cuFft_GetVersionString(char* sz, size_t* pLength)
{
	int driverVersion, runTimeVersion;
	if (cuFft_CheckAvailabilityAndGetVersions(&driverVersion, &runTimeVersion) == false)
	{
		return copyToDestString("ERROR", sz, pLength);
	}

	int cufftVersion;
	if (cufftGetVersion(&cufftVersion) != CUFFT_SUCCESS)
	{
		return copyToDestString("ERROR", sz, pLength);
	}

	std::stringstream ss;
	ss << "driver=" << driverVersion << ", runtime=" << runTimeVersion << ", cufft=" << cufftVersion;
	return copyToDestString(ss.str().c_str(), sz, pLength);
}